package com.fyb.basic.juc.completableFuture;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

/**
 * @Author：MR.FANG
 * @name：CompletableFutureMain
 * @Date：2025/7/2 下午2:28
 */
public class CompletableFutureMain {

    public static void main(String[] args) throws ExecutionException, InterruptedException {

        // 1、runAsync 异步执行 没有返回值
//         runAsync();

        // 2、supplyAsync 异步执行 有返回值
//         supplyAsync();

        // 3、get() 方法在Future 计算完成之前会一直处在 blocking 状态下 可以通过传入回调函数，在Future 结束时自动调用该回调函数
        // 串行处理 把上一个任务的执行结果作为下一个任务的输入 串行处理的后续操作不一定和前序操作使用同一个线程
//         thenApply();

        // 4、thenAccept 如果不想从回调函数中返回任何结果
//         thenAccept();

        // 5、thenRun 只能做串行处理 拿不到上一个任务的结果 因为它的回调函数式表达式定义中没有任何参数
//         thenRun();

        // 6、thenCombine 用来聚合两个独立的thenCombine 任务的结果  其实是为了解决上面串行出现嵌套的问题
//         thenCombine();

        // 7、allOf ｜ anyOf 用来聚合多个 CompletableFuture
//         allOF();

        // 8、异常处理 exceptionally 就相当于 catch，出现异常，将会跳过 thenApply 的后续操作，直接捕获异常
//         exectpitonally();

        // 9、handle 方法可以处理异常 用多线程，良好的习惯是使用 try/finally 范式，handle 就可以起到 finally 的作用，对上述程序做一个小小的更改， handle 接受两个参数，一个是正常返回值，一个是异常
//        handle();

        //10、allOf用来聚合多个 CompletableFuture
//        allOf1();
    }

    /**
     * try finally 异常处理
     * @throws InterruptedException
     * @throws ExecutionException
     */
    private static void handle() throws InterruptedException, ExecutionException {
        Integer age = -1;
        CompletableFuture<String> maturityFuture = CompletableFuture.supplyAsync(() -> {
            if( age < 0 ) {
                throw new IllegalArgumentException("何方神圣？");
            }
            if(age > 18) {
                return "大家都是成年人";
            } else {
                return "未成年禁止入内";
            }
        }).thenApply((str) -> {
            System.out.println("游戏开始");
            return str;
        }).handle((res, ex) -> {
            if(ex != null) {
                System.out.println("必有蹊跷，来者" + ex.getMessage());
                return "Unknown!";
            }
            return res;
        });
        System.out.println(maturityFuture.get());
    }

    /**
     * try catch 异常处理
     */
    private static void exectpitonally() {
        Integer age = -1;
        CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
            if (age < 0) {
                throw new RuntimeException("年龄不符合");
            }
            if (age > 18) {
                return "大家都是成年人";
            } else {
                return "未成年禁止入内";
            }
        }).thenApply(result -> {
            System.out.println("游戏开始");
            return result;
        }).exceptionally(e -> {
            System.out.println("发生异常：" + e.getMessage());
            return "发生异常";
        });
        System.out.println(completableFuture.join());
        System.out.println("主线程执行.......");
    }

    private static void allOF() {
        CompletableFuture<Double> widthCompletableFuture = CompletableFuture.supplyAsync(() -> 65.0);
        CompletableFuture<Double> heightCompletableFuture = CompletableFuture.supplyAsync(() ->  180.0);
        CompletableFuture.allOf(widthCompletableFuture, heightCompletableFuture).join();
    }

    /**
     * 聚合两个独立的 CompletableFuture 任务的结果
     * @throws InterruptedException
     * @throws ExecutionException
     */
    private static void thenCombine() throws InterruptedException, ExecutionException {
        CompletableFuture<Double> widthCompletableFuture = CompletableFuture.supplyAsync(() -> 65.0);
        CompletableFuture<Double> heightCompletableFuture = CompletableFuture.supplyAsync(() -> 180.0);
        CompletableFuture<Void> completableFuture = widthCompletableFuture.thenCombine(heightCompletableFuture, (weight, height) -> {
            Double heightInMeter = height / 100;
            return weight / (heightInMeter * heightInMeter);
        }).thenAccept(result -> {
            System.out.println("身体BMI指标计算结果：" + result);
        });
        completableFuture.get();
    }

    /**
     * thenRun 只能做串行处理 拿不到上一个任务的结果 因为它的回调函数式表达式定义中没有任何参数
     * @throws InterruptedException
     * @throws ExecutionException
     */
    private static void thenRun() throws InterruptedException, ExecutionException {
        CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(() -> {
            //前序操作
            System.out.println("异步执行我正在处理中.....");
        }).thenRun(() -> {
            //串行的后需操作，无参数也无返回值
            System.out.println("异步执行我处理完了.....");
        });
        completableFuture.get();
        System.out.println("主线程执行.......");
    }

    /**
     * thenAccept 如果不想从回调函数中返回任何结果  串行处理
     * @throws InterruptedException
     * @throws ExecutionException
     */
    private static void thenAccept() throws InterruptedException, ExecutionException {
        CompletableFuture<Void> completableFuture = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return "赞";
        }).thenAccept(first -> {
            System.out.println(first + ", 在看");
        }).thenAccept(second -> {
            System.out.println(second + ", 转发");
        });
        // 阻塞等待回去返回结果
        System.out.println(completableFuture.get());
        System.out.println("主线程执行.......");
    }
    /**
     * 串行处理 回调函数中获取结果
     *
     * @throws InterruptedException
     * @throws ExecutionException
     */
    private static void thenApply() throws InterruptedException, ExecutionException {
        CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return "赞";
        }).thenApply(first -> {
            return first + ", 在看";
        }).thenApply(second -> second + ", 转发");
        // 阻塞等待回去范湖结果
        System.out.println(completableFuture.get());
        System.out.println("主线程执行.......");
    }

    /**
     * 获取异步线程执行的返回结果 带有返回值
     *
     * @throws InterruptedException
     * @throws ExecutionException
     */
    private static void supplyAsync() throws InterruptedException, ExecutionException {
        CompletableFuture<String> supplyAsyncFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("异步执行.....");
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return "异步执行完毕";
        });
        System.out.println("获取异步线程执行的返回结果：" + supplyAsyncFuture.get());
    }

    /**
     * 异步执行 没有返回值
     */
    private static void runAsync() {

        CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(() -> {
            System.out.println("异步执行.....");
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });
        // 2、join 方法用来获取completableFuture执行返回的结果
        completableFuture.join();
        System.out.println("主线程执行.......");
    }

    private static void allOf1(){
        CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {
            try {
                System.out.println(Thread.currentThread() + " cf1 do something....");
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("cf1 任务完成");
            return "cf1 任务完成";
        });

        CompletableFuture<String> cf2 = CompletableFuture.supplyAsync(() -> {
            try {
                System.out.println(Thread.currentThread() + " cf2 do something....");
//                int a = 1/0;
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("cf2 任务完成");
            return "cf2 任务完成";
        });

        CompletableFuture<String> cf3 = CompletableFuture.supplyAsync(() -> {
            try {
                System.out.println(Thread.currentThread() + " cf2 do something....");
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("cf3 任务完成");
            return "cf3 任务完成";
        });

        CompletableFuture<Void> cfAll = CompletableFuture.allOf(cf1, cf2, cf3);
        try {
            System.out.println("cfAll结果->" + cfAll.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}
